﻿// --------------------------------------------------------------------------------------------------------------------- 
// <copyright file="ForecastTrendCalculationTest.cs" company="Scrum for Team System">
//   None
// </copyright>
// <summary>
//   Defines the ForecastTrendCalculationTest type.
// </summary>
// ---------------------------------------------------------------------------------------------------------------------
namespace ScrumForTeamSystem.Metrics.Test
{
    using System;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Defines the ForecastTrendCalculationTest type.
    /// </summary>
    [TestClass]
    public class ForecastTrendCalculationTest
    {
        /// <summary>
        /// Test to prove that: The null values forecast should return null regardless of parameters.
        /// </summary>
        [TestMethod]
        public void The_null_values_forecast_should_return_null_regardless_of_parameters()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.None, false, ConcatData);
                Assert.IsFalse(actual[i].HasValue);
            }
        }

        /// <summary>
        /// Test to prove that: The three day moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_three_day_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                190.00,
                                166.00,
                                151.67,
                                130.67,
                                109.67,
                                88.67,
                                67.67,
                                46.67
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.ThreeDayMovingAverage, false, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The three day weighted moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_three_day_weighted_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                179.67,
                                160.67,
                                148.17,
                                121.83,
                                95.50,
                                69.17,
                                42.83,
                                16.50
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.ThreeDayWeightedMovingAverage, false, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The three day exponental moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_three_day_exponential_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected = new[]
                               {
                                       default(double?), 
                                       default(double?),
                                       190.00,
                                       171.00,
                                       156.00,
                                       127.50,
                                       99.00,
                                       70.50,
                                       42.00,
                                       13.50
                               };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.ThreeDayExponentialMovingAverage, false, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The five day moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_five_day_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                default(double?),
                                default(double?),
                                172.60,
                                147.60,
                                122.60,
                                97.60,
                                72.60,
                                47.60
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.FiveDayMovingAverage, false, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The five day weighted moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_five_day_weighted_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                default(double?),
                                default(double?),
                                159.40,
                                134.87,
                                110.33,
                                85.80,
                                61.27,
                                36.73
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.FiveDayWeightedMovingAverage, false, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The five day exponental moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_five_day_exponental_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                default(double?),
                                default(double?),
                                172.60,
                                148.07,
                                123.53,
                                99.00,
                                74.47,
                                49.93
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.FiveDayExponentialMovingAverage, false, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: Linear regression should return a sequence of values as indicated.
        /// </summary>
        [TestMethod]
        public void The_adjusted_linear_regression_forecast_should_return_a_sequence_of_values_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected = new[] { 208.14, 186.31, 164.49, 142.66, 120.83, 99.00, 77.17, 55.34, 33.51, 11.69 };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.LinearRegression, true, ConcatData);
                Assert.AreEqual(Math.Round(expected[i], 2), Math.Round(actual[i].Value, 2));
            }
        }

        /// <summary>
        /// Test to prove that: The adjusted three day moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_adjusted_three_day_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected = 
                    new[]
                        {
                                default(double?),
                                default(double?),
                                158.33, 
                                134.33, 
                                120.00, 
                                99.00, 
                                78.00, 
                                57.00, 
                                36.00, 
                                15.00
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.ThreeDayMovingAverage, true, ConcatData);
                
                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The adjusted three day weighted moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_adjusted_three_day_weighted_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                156.83, 
                                137.83, 
                                125.33, 
                                99.00, 
                                72.67, 
                                46.33, 
                                20.00, 
                                -6.33
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.ThreeDayWeightedMovingAverage, true, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The adjusted three day exponental moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_adjusted_three_day_exponential_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                161.50,
                                142.50,
                                127.50,
                                99.00,
                                70.50,
                                42.00,
                                13.50,
                                -15.00
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.ThreeDayExponentialMovingAverage, true, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The adjusted five day moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_adjusted_five_day_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                default(double?),
                                default(double?),
                                124.00,
                                99.00,
                                74.00,
                                49.00,
                                24.00,
                                -1.00
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.FiveDayMovingAverage, true, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The adjusted five day weighted moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_adjusted_five_day_weighted_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                default(double?),
                                default(double?),
                                123.53,
                                99.00,
                                74.47,
                                49.93,
                                25.40,
                                0.87
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.FiveDayWeightedMovingAverage, true, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The adjusted five day exponental moving average forecast should return a sequence as indicated.
        /// </summary>
        [TestMethod]
        public void The_adjusted_five_day_exponental_moving_average_forecast_should_return_a_sequence_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected =
                    new[]
                        {
                                default(double?),
                                default(double?),
                                default(double?),
                                default(double?),
                                123.53,
                                99.00,
                                74.47,
                                49.93,
                                25.40,
                                0.87
                        };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.FiveDayExponentialMovingAverage, true, ConcatData);

                if (expected[i].HasValue)
                {
                    Assert.AreEqual(Math.Round(expected[i].Value, 2), Math.Round(actual[i].Value, 2));
                }
                else
                {
                    Assert.IsFalse(actual[i].HasValue);
                }
            }
        }

        /// <summary>
        /// Test to prove that: The product linear regression should return a sequence of values as indicated.
        /// </summary>
        [TestMethod]
        public void The_product_linear_regression_forecast_should_return_a_sequence_of_values_as_indicated()
        {
            const string ConcatData = "224,184,162,152,141,99,,,,";

            var forcaster = new Forecasting();

            var actual = new double?[10];
            var expected = new[] { 193.08, 171.25, 149.42, 127.59, 105.76, 83.93, 62.1, 40.28, 18.45, -3.38 };

            for (var i = 0; i < actual.Length; i++)
            {
                actual[i] = forcaster.GetNextTrendValue(TrendType.ProductLinearRegression, true, ConcatData);
                Assert.AreEqual(Math.Round(expected[i], 2), Math.Round(actual[i].Value, 2));
            }
        }
    }
}